import { ConstraintType, EventsRes, ICurve, MathTool } from '@amcax/base';
import { csEvent } from '@app-cad/common/events/EventCenter';
import { calculatePoint, getAngle, getDotProduct } from '@app-cad/common/utils';
import { wsApi } from '@app-cad/server';
import { Vector3 } from 'three-legacy';
import {
  SKETCH_CENTEREVENTS,
  sketchEventCenter,
} from '../../../events/SketchEventCenter';
import CmdBase, { ReturnDataInfo } from '../../CmdBase';
import { Constraint, LinePickEve, TrackingData } from './types';

export default class CmdInteractor extends CmdBase {
  // 约束
  _constraint: Constraint;
  // mouse hover line
  // 辅助点
  trackingData: TrackingData = {
    line: null,
    label: null,
  };
  // 点击点的顺序
  private modifyPointArr: [Vector3, Vector3];
  private lineVector: Vector3;

  constructor() {
    super();
    this.registerEvents();
    this.assisGroup.clear();
  }

  reset() {
    this.assistPoints = [];
    this.modifyPointArr = null;
    this._constraint && (this._constraint.geoRelation = null);
    this.trackingData = {
      line: null,
      label: null,
    };
  }

  registerEvents() {
    csEvent()
      .setState('cmdSketchEditLine')
      .on(SKETCH_CENTEREVENTS.POINTERMOVE, this.onMouseMove)
      .on(SKETCH_CENTEREVENTS.POINTERDOWN, this.onMouseDown)
      .addExit(this.destroy.bind(this));
  }

  unregisterEvents() {
    csEvent()
      .setDefault()
      .off(SKETCH_CENTEREVENTS.POINTERMOVE, this.onMouseMove)
      .off(SKETCH_CENTEREVENTS.POINTERDOWN, this.onMouseDown);
  } // 按下移动
  onMouseDown = (ev: EventsRes) => {
    this.setPickedCurve(this.picker.select(ev.event as PointerEvent, ev.mouse));
  }; // 鼠标按下
  onMouseMove = (ev: EventsRes) => {
    this.picker.pick(ev, { line: true });
  }; // 鼠标移动
  releaseObjects() {}

  setPickedCurve(value: ICurve) {
    if (value?.id) {
      const vertexs = value?.vertices || null;
      const point1 = new Vector3(...vertexs[0], 0);
      const point2 = new Vector3(...vertexs[1], 0);
      // 向量
      this.setVector([point1, point2]);
      // id
      this.pickedCurve = value;
      // 计算角度
      if (vertexs && vertexs.length >= 2) {
        const angle = getAngle(point2, point1);
        const length = point2.distanceTo(point1);
        sketchEventCenter().emit(LinePickEve.SKETCH_LINE_INFO, {
          lineLength: length,
          lineAngle: MathTool.radToDeg(angle),
          geoRelation: null,
        });
      }
    } else {
      this.exitFunc();
    }
  }

  // 添加约束
  addConstraint() {
    switch (this._constraint.geoRelation) {
      case ConstraintType.Dimension:
        this.editLength();
        break;

      case ConstraintType.Angle:
        this.editAngle();
        break;
    }
  }

  // 修改线段参数
  modifyLine() {
    const [point1, point2] = this.modifyPointArr;
    this.pickedCurve.vertices = [
      [point1.x, point1.y],
      [point2.x, point2.y],
    ];
    const angle = getAngle(point2, point1);
    // 线段长度
    sketchEventCenter().emit(LinePickEve.SKETCH_LINE_INFO, {
      lineLength: point1.distanceTo(point2),
      lineAngle:
        this._constraint.geoRelation !== ConstraintType.Angle
          ? MathTool.radToDeg(angle)
          : this._constraint.lineAngle,
    });
    this.setVector(this.modifyPointArr);
  }

  // 编辑线段长度
  editLength() {
    const vertexs = this.pickedCurve?.vertices;
    const point1 = new Vector3(...vertexs[0], 0);
    const point2 = new Vector3(...vertexs[1], 0);
    const endPoint =
      this._constraint.lineLength != null
        ? calculatePoint(this.lineVector, this._constraint.lineLength, point1)
        : point2;
    this.modifyPointArr = [point1, endPoint];
    this.cadModifyLine();
  }

  // 编辑线段角度
  editAngle() {
    const vertexs = this.pickedCurve?.vertices;
    const point1 = new Vector3(...vertexs[0], 0);
    const point2 = new Vector3(...vertexs[1], 0);
    const endPoint =
      this._constraint.lineAngle != null
        ? this.calculateNewPoint(point1, point2, this._constraint.lineAngle)
        : point2;
    this.modifyPointArr = [point1, endPoint];
    this.cadModifyLine();
  }

  // 更新法向
  setVector(vertexs: [Vector3, Vector3]) {
    const vec = new Vector3();
    vec.subVectors(vertexs[1], vertexs[0]).normalize();
    this.lineVector = vec;
  }

  // 修改线段
  cadModifyLine() {
    const [point1, point2] = this.modifyPointArr;
    if (!point1 || !point2) {
      return;
    }
    this.modifyLine();
    this.coreEditLine({
      point1: [point1.x, point1.y],
      point2: [point2.x, point2.y],
    });
  }

  async coreEditLine(params) {
    if (!this.pickedCurve?.id) {
      return;
    }
    const curveId = this.pickedCurve?.id;
    const modifyData: ReturnDataInfo = await wsApi.editSketchCurve(
      this.sketchId,
      this.pickedCurve.type,
      { ...params, curve: curveId },
    );
    if (!modifyData.changed.includes(this.pickedCurve.id)) {
      modifyData.changed.push(this.pickedCurve.id);
    }
    this.render(modifyData);
  }

  // 计算新点的位置
  calculateNewPoint(startPoint: Vector3, endPoint: Vector3, angle: number) {
    const distance = startPoint.distanceTo(endPoint);
    // 判断开始点是否等于结束点
    if (startPoint.equals(endPoint)) {
      return endPoint;
    } else {
      const radian = MathTool.degToRad(angle);
      const isSymbol =
        getDotProduct(startPoint, endPoint, this.lineVector) >= 0 ? 1 : -1;
      const newPoint = new Vector3(
        startPoint.x + distance * Math.cos(radian) * isSymbol,
        startPoint.y + distance * Math.sin(radian) * isSymbol,
        0,
      );
      return newPoint;
    }
  }
}
